#include <Memory/Paging.h>
#include <Utility/CLib.h>
#include <Kernel/GlobalData.h>
#include <IntExcept/Debug.h>
#include <IntExcept/Error.h>

/*
@brief 为内核分配栈帧
@return 栈底地址
@note PTE 第 9 位置为 1，P 位置 0
*/
LPVOID AllocateStackForKernel()
{
    LPVOID lpRet = NULL;
    QWORD dwAttrbuteBits = (PTE_USER | PTE_WRITEABLE);
    /* 分页后，页表在逻辑上是连续的 */
    BOOL bSuccess = FALSE;
    /* 遍历页表，此过程中若页表缺失，则会触发 #PF，由中断处理程序补充该页表的定义 */
    for (int i = 1021; i >= 768 && !bSuccess; i--) /* 遍历页表 */
    {
        for (int j = 1022; j >= 0; j -= 2) /* 每次检测两个连续的页表项 */
        {
            if ( /* 页表项中 P 位和 A 位均为 0 */
                ((g_MasterPageTable[i][j] & (PTE_PRESENT | PTE_ALLOCATED))) == 0 &&
                ((g_MasterPageTable[i][j + 1] & (PTE_PRESENT | PTE_ALLOCATED)) == 0)
            ) {
                g_MasterPageTable[i][j] |= PTE_ALLOCATED | PTE_WRITEABLE;
                g_MasterPageTable[i][j + 1] |= PTE_ALLOCATED | PTE_WRITEABLE;
                /* 分配物理页框 */
                if ( /* 栈不能发生缺页 */
                    AllocateFrame(&g_MasterPageTable[i][j]) &&
                AllocateFrame(&g_MasterPageTable[i][j + 1])
                ) {
                    bSuccess = TRUE;
                    lpRet = (LPVOID)GENERATE_VIRTUAL_ADDRESS(i, j, 0);
                    break;
                }
            }
        }
    }
    if (!bSuccess)
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY); /* 找不到连续虚拟页面 */
        return lpRet;
    }
    SetLastError(ERROR_SUCCESS);
    return lpRet;
}